﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Vds2465Telegrams;

namespace Vds2465Parser
{
	internal class VariableLength
	{
		#region internal constants

		internal const byte StartByteValue = 0x68;
		internal const byte AfterLengthByteValue = 0x68;
		internal const byte EndByteValue = 0x16;

		internal const byte MinLengthOfTelegram = 8;

		internal const byte PositionOfLengthField = 1;

		internal const byte PositionOfControlField = 4;
		internal const byte PositionOfAddressByte = 5;

		internal const byte PositionOfUserDataBytes = 6;

		#endregion constants

		#region internal methods

		internal static Telegram Parse_VariableLengthTelegram(byte[] variableLengthTelegramBytes)
		{
			bool calling;
			ControlField.IsThisCallingOrReturning(variableLengthTelegramBytes[PositionOfControlField], out calling);
			if (calling)
			{
				return Parse_VariableLengthTelegram_Calling(variableLengthTelegramBytes);
			}
			else
			{
				return Parse_VariableLengthTelegram_Returning(variableLengthTelegramBytes);
			}
		}

		internal static byte[] GetUserDataBytes(byte[] variableLengthTelegramBytes)
		{
			if (variableLengthTelegramBytes != null)
			{
				if (variableLengthTelegramBytes.Length >= MinLengthOfTelegram)
				{
					int lengthValue = variableLengthTelegramBytes[PositionOfLengthField];
					int lengthOfUserDataBytes = lengthValue - 2;
					if (lengthOfUserDataBytes >= 0)
					{
						byte[] userDataBytes = new byte[lengthOfUserDataBytes];
						for (int index=0; index < lengthOfUserDataBytes; index++)
						{
							userDataBytes[index] = variableLengthTelegramBytes[PositionOfUserDataBytes + index];
						}
						
						return userDataBytes;
					}

					// TODO handle error (wrong value for length in bytes)
					return null;
				}

				// TODO handle error (too short i.e. too few bytes)
				return null;
			}
			
			return null;
		}

		#endregion internal methods

		#region private methods

		private static Telegram Parse_VariableLengthTelegram_Calling(byte[] variableLengthTelegramCallingBytes)
		{
			eDirection direction;
			bool frameCountValid;
			bool frameCountFlag;
			eTelegramFunction_Calling telegramFunction;
			bool bRetVal = ControlField.Parse_ControlField_Calling(variableLengthTelegramCallingBytes[PositionOfControlField], out direction, out frameCountValid, out frameCountFlag, out telegramFunction);
			if (bRetVal)
			{
				if (telegramFunction == eTelegramFunction_Calling.SEND_NDAT)
				{
					return GenParse_SEND_NDAT.ParseBytes(variableLengthTelegramCallingBytes, direction, frameCountValid, frameCountFlag);
				}

				// TODO handle error (there is no other calling variable length telegram)
				return null;
			}

			// TODO handle error
			return null;
		}

		private static Telegram Parse_VariableLengthTelegram_Returning(byte[] variableLengthTelegramReturningBytes)
		{
			eDirection direction;
			bool accessDemandFlag;
			bool dataFlowControlStopFlag;
			eTelegramFunction_Returning telegramFunction;
			bool bRetVal = ControlField.Parse_ControlField_Returning(variableLengthTelegramReturningBytes[PositionOfControlField], 
						out direction, out accessDemandFlag, out dataFlowControlStopFlag, out telegramFunction);
			if (bRetVal)
			{
				if (telegramFunction == eTelegramFunction_Returning.RESPOND_NDAT)
				{
					return GenParse_Returning_RESPOND_NDAT.ParseBytes(variableLengthTelegramReturningBytes, direction, accessDemandFlag, dataFlowControlStopFlag);
				}

				if (telegramFunction == eTelegramFunction_Returning.CONFIRM_ACK)
				{
					return GenParse_Returning_CONFIRM_ACK.ParseBytes(variableLengthTelegramReturningBytes, direction, accessDemandFlag, dataFlowControlStopFlag);
				}

				// TODO handle error (there is no other calling variable length telegram)
				return null;
			}

			// TODO handle error
			return null;
		}

		#endregion private methods
	}
}
